﻿// *----------------------------------------------------------------
// Copyright (C) 2017 通通优品
// 版权所有。
// 
// 类名：Database.cs
// 功能描述：TongTongMall.Dapper
// 
// Create User：jym 2017/02/09
// 
// Edit User：UserName,EditTime
// Describe：Describe
// ----------------------------------------------------------------*/
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using TongTongMall.Dapper.DapperExtensions.Mapper;
using TongTongMall.Dapper.DapperExtensions.Sql;
using TongTongMall.Domain.PredicateForDapper;

namespace TongTongMall.Dapper.DapperExtensions
{
    public class Database : IDatabase
    {
        private readonly IDapperImplementor _dapper;

        private IDbTransaction _transaction;

        public IDbConnection Connection { get; private set; }

        public void SetConnection(IDbConnection DbConnection)
        {
            Connection = DbConnection;
        }

        public Database(IDapperImplementor dapper)
        {
            _dapper = dapper;
        }

        public bool HasActiveTransaction
        {
            get
            {
                return _transaction != null;
            }
        }

        public IDbTransaction BeginTransaction(IsolationLevel isolationLevel = IsolationLevel.ReadCommitted)
        {
            if (Connection.State != ConnectionState.Open)
            {
                Connection.Open();
            }
            _transaction = Connection.BeginTransaction(isolationLevel);
            return _transaction;
        }

        public void Commit()
        {
            _transaction.Commit();
            _transaction.Dispose();
            if (Connection.State != ConnectionState.Closed)
            {
                Connection.Close();
            }
            _transaction = null;
        }

        public void Rollback()
        {

            _transaction.Rollback();
            _transaction.Dispose();
            if (Connection.State != ConnectionState.Closed)
            {
                Connection.Close();
            }
            _transaction = null;
        }

        public void RunInTransaction(Action action)
        {
            BeginTransaction();
            try
            {
                action();
                Commit();
            }
            catch (TongTongMallException ex)
            {
                if (HasActiveTransaction)
                {
                    Rollback();
                }
                throw ex;
            }
        }

        public T RunInTransaction<T>(Func<T> func)
        {
            BeginTransaction();
            try
            {
                T result = func();
                Commit();
                return result;
            }
            catch (Exception ex)
            {
                if (HasActiveTransaction)
                {
                    Rollback();
                }

                throw ex;
            }
        }

        public dynamic Insert<T>(T entity, IDbTransaction transaction, int? commandTimeout) where T : class,new()
        {
            return _dapper.Insert<T>(Connection, entity, transaction, commandTimeout);
        }

        public dynamic Insert<T>(T entity, int? commandTimeout) where T : class,new()
        {
            return _dapper.Insert<T>(Connection, entity, _transaction, commandTimeout);
        }

        public bool Update<T>(T entity, IDbTransaction transaction, int? commandTimeout) where T : class, new()
        {
            return _dapper.Update<T>(Connection, entity, transaction, commandTimeout);
        }

        public bool Update<T>(T entity, int? commandTimeout) where T : class, new()
        {
            return _dapper.Update<T>(Connection, entity, _transaction, commandTimeout);
        }
        public bool Update<T>(object entity, object id, IDbTransaction transaction, int? commandTimeout) where T : class,new()
        {
            return _dapper.Update<T>(Connection, entity, id, transaction, commandTimeout);
        }

        public bool Update<T>(object entity, object whereClip, int? commandTimeout) where T : class,new()
        {
            return _dapper.Update<T>(Connection, entity, whereClip, _transaction, commandTimeout);
        }

        public bool Delete<T>(object predicate, IDbTransaction transaction, int? commandTimeout) where T : class,new()
        {
            return _dapper.Delete<T>(Connection, predicate, transaction, commandTimeout);
        }

        public bool Delete<T>(object predicate, int? commandTimeout) where T : class,new()
        {
            return _dapper.Delete<T>(Connection, predicate, _transaction, commandTimeout);
        }

        public IEnumerable<T> GetList<T>(object predicate, IList<ISort> sort, IDbTransaction transaction, Expression<Func<T, object>> selector, int? commandTimeout, bool buffered) where T : class,new()
        {
            return _dapper.GetList<T>(Connection, predicate, sort, transaction, selector, commandTimeout, buffered);
        }

        public IEnumerable<T> GetList<T>(object predicate, IList<ISort> sort, Expression<Func<T, object>> selector, int? commandTimeout, bool buffered) where T : class, new()
        {
            return _dapper.GetList<T>(Connection, predicate, sort, _transaction, selector, commandTimeout, buffered);
        }

        public int Count<T>(object predicate, IDbTransaction transaction, int? commandTimeout) where T : class,new()
        {
            return _dapper.Count<T>(Connection, predicate, transaction, commandTimeout);
        }

        public int Count<T>(object predicate, int? commandTimeout) where T : class,new()
        {
            return _dapper.Count<T>(Connection, predicate, _transaction, commandTimeout);
        }


        public void ClearCache()
        {
            _dapper.SqlGenerator.Configuration.ClearCache();
        }

        public Guid GetNextGuid()
        {
            return _dapper.SqlGenerator.Configuration.GetNextGuid();
        }

        public IClassMapper GetMap<T>() where T : class,new()
        {
            return _dapper.SqlGenerator.Configuration.GetMap<T>();
        }

        public async Task<dynamic> InsertAsync<T>(T entity, IDbTransaction transaction, int? commandTimeout = default(int?)) where T : class,new()
        {
            return await _dapper.InsertAsync<T>(Connection, entity, transaction, commandTimeout);
        }

        public async Task<dynamic> InsertAsync<T>(T entity, int? commandTimeout = default(int?)) where T : class,new()
        {
            return await _dapper.InsertAsync<T>(Connection, entity, _transaction, commandTimeout);
        }
        public async Task<bool> UpdateAsync<T>(T entity, IDbTransaction transaction, int? commandTimeout = default(int?)) where T : class, new()
        {
            return await _dapper.UpdateAsync<T>(Connection, entity, transaction, commandTimeout);
        }

        public async Task<bool> UpdateAsync<T>(T entity, int? commandTimeout = default(int?)) where T : class, new()
        {
            return await _dapper.UpdateAsync<T>(Connection, entity, _transaction, commandTimeout);
        }

        public async Task<bool> UpdateAsync<T>(object entity, object id, IDbTransaction transaction, int? commandTimeout = default(int?)) where T : class,new()
        {
            return await _dapper.UpdateAsync<T>(Connection, entity, id, transaction, commandTimeout);
        }

        public async Task<bool> UpdateAsync<T>(object entity, object whereClip, int? commandTimeout = default(int?)) where T : class,new()
        {
            return await _dapper.UpdateAsync<T>(Connection, entity, whereClip, _transaction, commandTimeout);
        }

        public async Task<bool> DeleteAsync<T>(object predicate, IDbTransaction transaction, int? commandTimeout = default(int?)) where T : class,new()
        {
            return await _dapper.DeleteAsync<T>(Connection, predicate, transaction, commandTimeout);
        }

        public async Task<bool> DeleteAsync<T>(object predicate, int? commandTimeout = default(int?)) where T : class,new()
        {
            return await _dapper.DeleteAsync<T>(Connection, predicate, _transaction, commandTimeout);
        }

        public async Task<IEnumerable<T>> GetListAsync<T>(object predicate, IList<ISort> sort, IDbTransaction transaction, Expression<Func<T, object>> selector = null, int? commandTimeout = default(int?), bool buffered = true) where T : class,new()
        {
            return await _dapper.GetListAsync<T>(Connection, predicate, sort, transaction, selector, commandTimeout, buffered);
        }

        public async Task<IEnumerable<T>> GetListAsync<T>(object predicate = null, IList<ISort> sort = null, Expression<Func<T, object>> selector = null, int? commandTimeout = default(int?), bool buffered = true) where T : class,new()
        {
            return await _dapper.GetListAsync<T>(Connection, predicate, sort, _transaction, selector, commandTimeout, buffered);
        }

        public async Task<int> CountAsync<T>(object predicate, IDbTransaction transaction, int? commandTimeout = default(int?)) where T : class,new()
        {
            return await _dapper.CountAsync<T>(Connection, predicate, transaction, commandTimeout);
        }

        public async Task<int> CountAsync<T>(object predicate, int? commandTimeout = default(int?)) where T : class,new()
        {
            return await _dapper.CountAsync<T>(Connection, predicate, _transaction, commandTimeout);
        }


        public IEnumerable<T> QueryPaged<T>(int pageIndex, int pageSize, object whereClip = null, IList<ISort> orderClip = null, Expression<Func<T, object>> selector = null, int? commandTimeout = default(int?), bool buffered = true) where T : class,new()
        {
            return _dapper.QueryPaged<T>(Connection, pageIndex, pageSize, whereClip, orderClip, selector, _transaction, commandTimeout, buffered);
        }

        public async Task<IEnumerable<T>> QueryPagedAsync<T>(int pageIndex, int pageSize, object whereClip = null, IList<ISort> orderClip = null, Expression<Func<T, object>> selector = null, int? commandTimeout = default(int?)) where T : class, new()
        {
            return await _dapper.QueryPagedAsync<T>(Connection, pageIndex, pageSize, whereClip, orderClip, selector, _transaction, commandTimeout);
        }

    }
}
